/***************************************************************************************************
                                项目                :       GimKeyboard
                                处理器				:       ESP32-S3
                                开发环境			:       pio(Arduino)
                                文件				:       hc165_keyboard_matrix_drv.cpp
                                说明				:       74HC165驱动文件
                                作者				:       金欣嵘
====================================================================================================

====================================================================================================
                                               修改记录 
====================================================================================================
----------------------------------------------------------------------------------------------------
                                               2024.02.04
----------------------------------------------------------------------------------------------------
                            修改人                  :            金欣嵘
                            修改记录                :            创建文件 
----------------------------------------------------------------------------------------------------
***************************************************************************************************/
#include <Arduino.h>
#include "../inc/hc165_keyboard_matrix_drv.h"

TaskHandle_t KeyboardMatrixDrv::keyboard_matrix_task_handler = nullptr;
QueueHandle_t KeyboardMatrixDrv::keyboard_matrix_queue = nullptr;
SemaphoreHandle_t KeyboardMatrixDrv::matrix_sacn_begin_semaphore = nullptr;     //开始扫描信号

/***************************************************************************************************
 ---------------------------------------------------------------------------------------------------
 | 7           6    5    4    3         2    1    0   8         9   10  11  12  |  13   14   15
 | ESC         F1   F2   F3   F4        F5   F6   F7  F8        F9  F10 F11 F12 |  PS   SL   PB
 ---------------------------------------------------------------------------------------------------
 | 23    22    21    20    19    18    17    16   31   30   29   28   27   26   |  25   24   39
 | ~     1     2     3     4     5     6     7    8    9    0    -    +    BS   |  Ist  Home PU
 ---------------------------------------------------------------------------------------------------
 | 38      37   36   35   34   33   32   47   46   45   44   43   42   41       |  40   55   54
 | TAB     Q    W    E    R    T    Y    U    I    O    P    {    }    |        |  Del  END  PD
  ---------------------------------------------------------------------------------------------------
 | 53       52   51   50   49   48   63   62   61   60   59   58          57    |
 | CL       A    S    D    F    G    H    J    K    L    :    "           Ent   |
 ---------------------------------------------------------------------------------------------------
 | 56         71   70   69   68   67   66   65   64   79   78           77      |       76 
 | Sft        Z    X    C    V    B    N    M    <    >    /            Sft     |       ⬆ 
 ---------------------------------------------------------------------------------------------------
 | 75   74   73                     72                     87   86   85   84    |  83   82   81
 | Ctr  Win  Alt                    SP                     Alt  FN   Fil  Ctr   |  ⬅   ⬇    ➡
 ---------------------------------------------------------------------------------------------------
***************************************************************************************************/
uint8_t KeyboardMatrixDrv::trigger_matrix[HC165_NUM] = {0};

/***************************************************************************************************
  * @函数名称 : init
  * @函数功能 : 初始化键盘矩阵扫描任务
***************************************************************************************************/
#define HC165_CLK_PIN                           3                               //时钟引脚
#define HC165_PL_PIN                            5                               //数据获取引脚
#define HC165_CLK_EN_PIN                        4                               //时钟使能引脚
#define HC165_DATA_PIN                          2                               //数据输出引脚

void KeyboardMatrixDrv::init(void)
{
    /*GPIO INIT     BEGIN*/
    pinMode(HC165_CLK_PIN, OUTPUT);
    pinMode(HC165_PL_PIN, OUTPUT);
    pinMode(HC165_CLK_EN_PIN, OUTPUT);
    pinMode(HC165_DATA_PIN, INPUT);

    digitalWrite(HC165_PL_PIN, HIGH);
    digitalWrite(HC165_CLK_PIN, HIGH);
    digitalWrite(HC165_CLK_EN_PIN, LOW);
    /*GPIO INIT     END*/

    matrix_sacn_begin_semaphore = xSemaphoreCreateBinary();

    keyboard_matrix_queue = xQueueCreate(KEYBOARD_MATRIX_DRV_QUEUE_LEN, HC165_NUM);

    xTaskCreate(start_keyboard_matrix_task,
    "keyboardMatrixTask",
    KEYBOARD_MATRIX_DRV_TASK_STACK_SIZE,
    NULL,
    KEYBOARD_MATRIX_DRV_TASK_PRIO,
    &keyboard_matrix_task_handler);
}

/***************************************************************************************************
  * @函数名称 : lock_data
  * @函数功能 : 锁存数据
***************************************************************************************************/
#define HC165_LATCHING_TIME                     10                              //锁存时间

void KeyboardMatrixDrv::lock_data(void)
{
    digitalWrite(HC165_PL_PIN, LOW);
    delayMicroseconds(HC165_LATCHING_TIME);
    digitalWrite(HC165_PL_PIN, HIGH);
}

/***************************************************************************************************
  * @函数名称 : get_fn_key_state
  * @函数返回 : 返回FN按键是否按下
  * @函数功能 : 获取FN按键按下状态
***************************************************************************************************/
bool KeyboardMatrixDrv::get_fn_key_state(void)
{
    bool retVal = false;
    if (trigger_matrix[KEYBOARD_KEY_FN / HC165_DATA_PIN_NUM] |= KEYBOARD_RELEASE << (KEYBOARD_KEY_FN % HC165_DATA_PIN_NUM))
    {
        retVal = true; 
    }
    return retVal;
}


/***************************************************************************************************
  * @函数名称 : read_data
  * @函数功能 : 读取数据
***************************************************************************************************/
#define HC165_CLOCK_CYCLE                       10                              //时钟周期

void KeyboardMatrixDrv::read_data(void)
{
    memset(trigger_matrix, 0, sizeof(trigger_matrix));                          //读取前先清空

    for(uint16_t i = 0; i < HC165_NUM * HC165_DATA_PIN_NUM; i ++)
    {
        digitalWrite(HC165_CLK_PIN, LOW);
        delayMicroseconds(HC165_CLOCK_CYCLE);
        if(digitalRead(HC165_DATA_PIN) == HIGH)
        {
            trigger_matrix[i / HC165_DATA_PIN_NUM] |= KEYBOARD_RELEASE << (i % HC165_DATA_PIN_NUM);
        }
        else
        {
            trigger_matrix[i / HC165_DATA_PIN_NUM] |= KEYBOARD_PUSH << (i % HC165_DATA_PIN_NUM);
        }

#if KEYBOARD_MATRIX_DEBUG
        printf("%d", trigger_matrix[i / HC165_DATA_PIN_NUM] >> (i % HC165_DATA_PIN_NUM));
#endif

        digitalWrite(HC165_CLK_PIN, HIGH);
    }

#if KEYBOARD_MATRIX_DEBUG
    printf("\n");
#endif

    if (xQueueSendToBack(keyboard_matrix_queue, trigger_matrix, 0) != pdTRUE)
    {
#if KEYBOARD_MATRIX_DEBUG
        printf("[KEYBOARD MATRIX]Queue Full!");
#endif
    }
}

/***************************************************************************************************
  * @函数名称 : start_keyboard_matrix_task
  * @输入参数 : pvParameters：任务服务函数的参数（未使用）
  * @输出参数 : 无
  * @函数返回 : 无
  * @函数功能 : 任务服务函数
***************************************************************************************************/
void KeyboardMatrixDrv::start_keyboard_matrix_task(void *pvParameters)
{
#if KEYBOARD_MATRIX_DEBUG
    printf("=========keyboard matrix task is running!=========\r\n");
#endif

    for(;;)
    {
        xSemaphoreTake(matrix_sacn_begin_semaphore, portMAX_DELAY);             //死等开始扫描信号量
        lock_data();
        read_data();
        vTaskDelay(1);
    }

#if KEYBOARD_MATRIX_DEBUG
    printf("============keyboard matrix task is end!==========\r\n");
#endif
}

KeyboardMatrixDrv keyboard_matrix_drv;
